﻿using Grpc.Core;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using RSTAi.Platform.GrpcService.Common;
using RSTAi.Platform.GrpcService.Contexts;
using RSTAi.Platform.GrpcService.Models;


namespace RSTAi.Platform.GrpcService.Services
{

    public class ProductServices : IProductServices.IProductServicesBase
    {
        private readonly MyDBContext _dBContext;
        private readonly ILogger<ProductServices> _logger;
        private readonly IPushServices.IPushServicesClient _pushServicesClient;//推送 
        public ProductServices(MyDBContext dBContext, ILogger<ProductServices> logger, IPushServices.IPushServicesClient pushServicesClient)
        {
            this._dBContext = dBContext;
            _logger = logger;
            _pushServicesClient = pushServicesClient;
        }

        /// <summary>
        /// 获取产品列表 先读缓存
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductDto> GetProductList(ProductListFrom request, ServerCallContext context)
        {

            ResponeProductDto dto = new ResponeProductDto();
            string message = string.Empty;
            try
            {
                if (string.IsNullOrWhiteSpace(request.StationId))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "StationId cannot be empty";
                    return dto;
                }
                var products = await _dBContext.Products.Where(c => c.StationId == request.StationId).ToListAsync();

                #region 可以推送到服务端

                //CurrentOrderFrom currentOrderFrom =new CurrentOrderFrom();
                //ResponeCurrentOrderDto orderDto = _pushServicesClient.PushCurrentOrder(currentOrderFrom);

                #endregion

                if (products.Any())
                {
                    products.ForEach(c =>
                    {
                        dto.Content.Add(Exchage(c));
                    });
                }

                dto.IsSuccess = true;
                dto.Code = 100;
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "GetProductList");

            }
            return dto;
        }

        /// <summary>
        /// 获取产品  
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductDto> GetProduct(ProductFrom request, ServerCallContext context)
        {
            ResponeProductDto dto = new ResponeProductDto();
            string message = string.Empty;
            try
            {
                if (string.IsNullOrWhiteSpace(request.StationId))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "StationId cannot be empty";
                    return dto;
                }


                var product = await _dBContext.Products.FirstOrDefaultAsync(c => c.ProductName == request.ProductName && c.StationId == request.StationId);
                if (product != null && !string.IsNullOrEmpty(product?.ProductName))
                {
                    dto.Content.Add(Exchage(product));
                }
                dto.IsSuccess = true;
                dto.Code = 100;
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "GetProduct");

            }
            return dto;
        }
        
        /// <summary>
        /// 新增产品  更新缓存
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductDto> AddProduct(AddProductFrom request, ServerCallContext context)
        {
            ResponeProductDto dto = new ResponeProductDto();
            string message = string.Empty;
            try
            {
                if (string.IsNullOrWhiteSpace(request.StationId))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "StationId cannot be empty";
                    return dto;
                }
                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductName cannot be empty";
                    return dto;
                }

                var product =await  _dBContext.Products.FirstOrDefaultAsync(c => c.StationId == request.StationId && c.ProductName == request.ProductName);
                if (!string.IsNullOrEmpty(product?.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 102;
                    dto.Message = "ProductName  already exists!";
                    return dto;
                }
                Models.Product model = new Models.Product()
                {
                    ProductNo = UUID.GenerateLongUUID(),
                    ProductName = request.ProductName,
                    CallId = request.CallId,
                    StationId = request.StationId,
                };
                await _dBContext.Products.AddAsync(model);
                await _dBContext.SaveChangesAsync();
                dto.Content.Add(Exchage(model));
                dto.IsSuccess = true;
                dto.Code = 100;

                
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "AddProduct");

            }
            return dto;
        }

        /// <summary>
        /// 删除产品和它关联的流程，更新缓存
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductDto> DeleteProduct(DeleteProductFrom request, ServerCallContext context)
        {
            ResponeProductDto dto = new ResponeProductDto();
            string message = string.Empty;
            try
            {
                
                if (string.IsNullOrWhiteSpace(request.StationId))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "StationId cannot be empty";
                    return dto;
                }
                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductNo cannot be empty";
                    return dto;
                }

                var product = await _dBContext.Products.Include(e => e.ProductSteps).FirstOrDefaultAsync(c => c.ProductName == request.ProductName && c.StationId == request.StationId);
                if (product == null && string.IsNullOrEmpty(product?.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 102;
                    dto.Message = "product not exists!";
                    return dto;
                }
                _dBContext.Products.Remove(product);
                await _dBContext.SaveChangesAsync();
                dto.IsSuccess = true;
                dto.Code = 100;
                
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "DeleteProduct");

            }
            return dto;
        }


        /// <summary>
        /// 获得产品流程  先取缓存中的数据，不存在则直接读取文件
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductStepDto> GetProductStep(ProductStepFrom request, ServerCallContext context)
        {

            ResponeProductStepDto dto = new ResponeProductStepDto();
            string message = string.Empty;
            try
            {

                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductName cannot be empty";
                    return dto;
                }

                long productNo = 0;
                if (!long.TryParse(request.ProductNo, out productNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductNo must be a number";
                    return dto;
                }


                var productSteps = await _dBContext.ProductSteps.Where(c => c.ProductName == request.ProductName && c.ProductNo == productNo).OrderBy(c => c.Step).ToListAsync();
                if (productSteps != null && productSteps.Any())
                {
                    //var list = await products.ToListAsync();
                    productSteps.ForEach(c =>
                    {

                        dto.Content.Add(new ProductStepDto()
                        {
                            ProductStepNo = c.ProductStepNo.ToString(),
                            ProductName = c.ProductName,
                            ProductNo = c.ProductNo.ToString(),
                            ProductStepName = c.ProductStepName,
                            Input = c.Input,
                            Remark = c.Remark,
                            Step = c.Step,
                            X = c.X,
                            Y = c.Y,
                            Parameter = c.Parameter,
                            UnionId = c.UnionId,
                        });
                    });
                }


                dto.IsSuccess = true;
                dto.Code = 100;
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "GetProductStep");

            }
            return dto;
        }

       

        /// <summary>
        /// 增加产品流程  增加后需要重新调整step的值
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductStepDto> AddProductStep(AddProductStepFrom request, ServerCallContext context)
        {
            ResponeProductStepDto dto = new ResponeProductStepDto();
            string message = string.Empty;
            try
            {
                
                if (string.IsNullOrWhiteSpace(request.StationId))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "StationId cannot be empty";
                    return dto;
                }
                if (string.IsNullOrWhiteSpace(request.ProductStepName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductStepName cannot be empty";
                    return dto;
                }
                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductName cannot be empty";
                    return dto;
                }
                int maxStep = 0;
                int step = 0;

                IQueryable<Product> products = _dBContext.Products.
                    Where(p => p.ProductName == request.ProductName && p.StationId == request.StationId).
                    Include(b => b.ProductSteps);
                //(c => c.ProductName == request.ProductName && c.StationId == request.StationId).Result;

                if (products == null || !products.Any())
                {
                    dto.IsSuccess = false;
                    dto.Code = 103;
                    dto.Message = "ProductName not exists!";
                    return dto;

                }

                //var productSteps =  _dBContext.ProductSteps.FromSql<ProductStep>($"SELECT * FROM dbo.Blogs").ToList(); //.MaxAsync(c=>c.Step);

                var product = products.FirstOrDefault<Product>();
                if (product == null)
                {
                    dto.IsSuccess = false;
                    dto.Code = 103;
                    dto.Message = "ProductName not exists!";
                    return dto;
                }
                var productSteps = product.ProductSteps;
                if ( productSteps.Any())
                {
                    maxStep = productSteps.Max(c => c.Step);
                    if (maxStep + 1 < request.Step)
                        step = maxStep + 1;
                    else
                    {
                        productSteps.ForEach(c =>
                        {
                            if (c.Step >= request.Step)
                                c.Step++;

                        });
                        step = request.Step;
                    }

                }

                ProductStep model = new ProductStep()
                {

                    ProductStepNo = UUID.GenerateLongUUID(),
                    ProductStepName = request.ProductStepName,
                    ProductNo = product.ProductNo,
                    ProductName = request.ProductName,
                    Input = request.Input,
                    Remark = request.Remark,
                    Step = step,
                    X = request.X,
                    Y= request.Y

            };
                await _dBContext.ProductSteps.AddAsync(model);
                await _dBContext.SaveChangesAsync();
                dto.Content.Add(new ProductStepDto()
                {
                    ProductStepNo = model.ProductStepNo.ToString(),
                    ProductStepName = model.ProductStepName,
                    ProductNo = model.ProductNo.ToString(),
                    ProductName = model.ProductName,
                    Input = model.Input,
                    Remark = model.Remark,
                    Step = step,
                    X = model.X,
                    Y = model.Y,
                    Parameter=model.Parameter
                });
                dto.IsSuccess = true;
                dto.Code = 100;
                
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "AddProduct");

            }
            return dto;
        }

        /// <summary>
        /// 删除流程、删除流程后需要重新调整step的值
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductStepDto> DeleteProductStep(DeleteProductStepFrom request, ServerCallContext context)
        {
            ResponeProductStepDto dto = new ResponeProductStepDto();
            string message = string.Empty;
            try
            {
               

                long productStepNo = 0;
                if (!long.TryParse(request.ProductStepNo, out productStepNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductStepNo must be a number";
                    return dto;
                }

                long productNo = 0;
                if (!long.TryParse(request.ProductNo, out productNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductNo must be a number";
                    return dto;
                }

               
                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductName cannot be empty";
                    return dto;
                }
                var productSteps = await _dBContext.ProductSteps.Where(c => c.ProductNo == productNo && c.ProductName==request.ProductName).OrderBy(c => c.Step).ToListAsync();
                int step = 0;
                if (productSteps.Any())
                {
                    var productStep = productSteps.FirstOrDefault(c => c.ProductStepNo == productStepNo);
                    if (productStep != null)
                    {
                        step = productStep.Step;
                        productSteps.Remove(productStep);
                        productSteps.ForEach(c =>
                        {
                            if (c.Step > step)
                            {
                                c.Step = step;
                                step++;
                            }
                            //处理返回值
                            dto.Content.Add(new ProductStepDto()
                            {
                                ProductStepNo = c.ProductStepNo.ToString(),
                                ProductName = c.ProductName,
                                ProductNo = c.ProductNo.ToString(),
                                ProductStepName = c.ProductStepName,
                                Input = c.Input,
                                Remark = c.Remark,
                                Step = step,
                                X = c.X,
                                Y = c.Y,
                                Parameter = c.Parameter
                            });
                        });
                        _dBContext.ProductSteps.Remove(productStep);
                    }
                    await _dBContext.SaveChangesAsync();
                }
                
                dto.IsSuccess = true;
                dto.Code = 100;
                
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "DeleteProductStep");

            }
            return dto;
        }

        /// <summary>
        /// 修改流程顺序 当修改后的流程大于等于当前最大流程时，不修改流程顺序，当修改后的流程在
        ///小于当前最大流程，
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductStepDto> UpdateStep(UpdateStepFrom request, ServerCallContext context)
        {
            ResponeProductStepDto dto = new ResponeProductStepDto();
            string message = string.Empty;
            try
            {
               
                long productStepNo = 0;
                if (long.TryParse(request.ProductStepNo, out productStepNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductStepNo cannot be empty";
                    return dto;
                }
                long productNo = 0;
                if (long.TryParse(request.ProductNo, out productNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductNo cannot be empty";
                    return dto;
                }
                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductName cannot be empty";
                    return dto;
                }

                if (request.Step > 0)
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "Step must be greater than 0";
                    return dto;
                }
                int step = 0;
                var productSteps = await _dBContext.ProductSteps.Where(c => c.ProductNo == productNo && c.ProductName == request.ProductName).ToListAsync();
                if (productSteps.Any())
                {
                    step = request.Step;
                    int max = productSteps.Max(c => c.Step);
                    productSteps.OrderBy(c => c.Step).ToList().ForEach(c =>
                    {
                        if (max > step)
                        {
                            if (c.ProductStepNo == productStepNo)
                            {
                                c.Step = step;
                            }

                            if (c.Step >= step)
                            {
                                c.Step++;
                            }
                        }
                        dto.Content.Add(new ProductStepDto()
                        {
                            ProductStepNo = c.ProductStepNo.ToString(),
                            ProductStepName = c.ProductStepName,
                            ProductNo = c.ProductNo.ToString(),
                            ProductName = c.ProductName,
                            Input = c.Input,
                            Remark = c.Remark,
                            Step = c.Step,
                            X = c.X,
                            Y = c.Y,
                            Parameter = c.Parameter,
                            UnionId = c.UnionId

                        });

                    });



                }
                await _dBContext.SaveChangesAsync();
                dto.IsSuccess = true;
                dto.Code = 100;

                
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "AddProduct");

            }
            return dto;
        }
        /// <summary>
        /// 修改流程参数
        /// </summary>
        /// <param name="request"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public override async Task<ResponeProductStepDto> UpdateStepParameter(UpdateProductStepFrom request, ServerCallContext context)
        {
            ResponeProductStepDto dto = new ResponeProductStepDto();
            string message = string.Empty;
            try
            {
              
                long productStepNo = 0;
                if (!long.TryParse(request.ProductStepNo, out productStepNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductStepNo must be a number";
                    return dto;
                }

                long productNo = 0;
                if (!long.TryParse(request.ProductNo, out productNo))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductNo must be a number";
                    return dto;
                }


                if (string.IsNullOrWhiteSpace(request.ProductName))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "ProductName cannot be empty";
                    return dto;
                }

                if (string.IsNullOrWhiteSpace(request.Parameter))
                {
                    dto.IsSuccess = false;
                    dto.Code = 101;
                    dto.Message = "Parameter cannot be empty";
                    return dto;
                }
                var productSteps = await _dBContext.ProductSteps.Where(c => c.ProductNo == productNo && c.ProductName == request.ProductName).OrderBy(c => c.Step).ToListAsync();
               
                if (productSteps != null && productSteps.Any())
                {
                    var productStep = productSteps.FirstOrDefault(c => c.ProductStepNo == productStepNo);
                    if (productStep != null)
                    {
                        productStep.Parameter = request.Parameter;

                        //处理返回值
                        dto.Content.Add(new ProductStepDto()
                        {
                            ProductStepNo = productStep.ProductStepNo.ToString(),
                            ProductName = productStep.ProductName,
                            ProductNo = productStep.ProductNo.ToString(),
                            ProductStepName = productStep.ProductStepName,
                            Input = productStep.Input,
                            Remark = productStep.Remark,
                            Step = productStep.Step,
                            X = productStep.X,
                            Y = productStep.Y,
                            Parameter = productStep.Parameter
                        });
                        //_dBContext.ProductSteps.Remove(productStep);
                    }
                    await _dBContext.SaveChangesAsync();
                }

                dto.IsSuccess = true;
                dto.Code = 100;
                
            }
            catch (Exception ex)
            {
                dto.IsSuccess = false;
                dto.Code = 999;
                dto.Message = ex.Message;
                _logger.LogError(ex.Message, "DeleteProductStep");

            }
            return dto;
        }

        /// <summary>
        /// 客户端流模式
        /// </summary>
        /// <param name="request"></param>
        /// <param name="responseStream"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async override Task GetProductToStream(ProductFrom request, IServerStreamWriter<ResponeProductDto> responseStream, ServerCallContext context)
        {
            ResponeProductDto dto=new ResponeProductDto();
            
            for (int i = 0; i < 10; i++)
            {
                //一次请求 多次返回结果
                await responseStream.WriteAsync(new ResponeProductDto() {  Code=100, IsSuccess=true });
                await Task.Delay(System.TimeSpan.FromSeconds(1));
            }
            
        }

        /// <summary>
        /// 服务端流模式
        /// </summary>
        /// <param name="requestStream"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async override Task<ResponeProductDto> GetStreamToProduct(IAsyncStreamReader<ProductFrom> requestStream, ServerCallContext context)
        {
            ResponeProductDto dto = new ResponeProductDto();
            List<ProductFrom> productFroms = new List<ProductFrom>();
            ProductFrom productFrom  = new ProductFrom();
            //多次请求 返回一次结果
            while (await requestStream.MoveNext())
            {
                productFrom = new ProductFrom()
                {
                    StationId = requestStream.Current.StationId,
                    ProductName = requestStream.Current.ProductName,


                };
                productFroms.Add(productFrom);
                Thread.Sleep(100);
            }

            return dto;
        }

        /// <summary>
        /// 双向流模式
        /// </summary>
        /// <param name="requestStream"></param>
        /// <param name="responseStream"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async override Task GetStreamToStream(IAsyncStreamReader<ProductFrom> requestStream, IServerStreamWriter<ResponeProductDto> responseStream, ServerCallContext context)
        {
            //多次请求 多次返回
            ResponeProductDto dto = new ResponeProductDto();

            List<ProductFrom> productFroms = new List<ProductFrom>();
            ProductFrom productFrom = new ProductFrom();
            //多次请求 多次返回结果
            while (await requestStream.MoveNext())
            {
                productFrom = new ProductFrom()
                {
                    StationId = requestStream.Current.StationId,
                    ProductName = requestStream.Current.ProductName,


                };
                productFroms.Add(productFrom);
                Thread.Sleep(100);
            }


            for (int i = 0; i < 10; i++)
            {
                //多次返回结果
                await responseStream.WriteAsync(new ResponeProductDto() { Code = 100, IsSuccess = true });
                await Task.Delay(System.TimeSpan.FromSeconds(1));
            }


        }
        private ProductDto Exchage(Product product)
        {
            return new ProductDto()
            {
                ProductNo = product.ProductNo.ToString(),
                ProductName = product.ProductName,
                CallId = product.CallId,
                StationId = product.StationId,


            };
        }

       
    }
}


